--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Node / ReticulumProjects / MeshChatX.git / files / meshchatx / src / backend / database / access_attempts.py
Displaying Raw • Download
meshchatx/src/backend/database/access_attempts.py 9cd0e66d8aa6dac478b6001f703ca6777f8f709c (9cd0e66d) Text, 7.30 KB
T8b949e# SPDX-License-Identifier: 0BSD
Tff7b72from T7ee787__future__ Tff7b72import Te6edf3annotations
Tff7b72import T7ee787hashlib
Tff7b72import T7ee787time
Tff7b72from T7ee787typing Tff7b72import Te6edf3Any
Tff7b72from T7ee787.T7ee787provider Tff7b72import Te6edf3DatabaseProvider
Te6edf3LOGIN_PATH Tff7b72= Ta5d6ff"Ta5d6ff/api/v1/auth/loginTa5d6ff"
Te6edf3SETUP_PATH Tff7b72= Ta5d6ff"Ta5d6ff/api/v1/auth/setupTa5d6ff"
Te6edf3WINDOW_RATE_UNTRUSTED_S Tff7b72= T79c0ff60
Te6edf3MAX_UNTRUSTED_LOGIN_PER_WINDOW Tff7b72= T79c0ff20
Te6edf3WINDOW_RATE_TRUSTED_S Tff7b72= T79c0ff60
Te6edf3MAX_TRUSTED_LOGIN_PER_WINDOW Tff7b72= T79c0ff120
Te6edf3WINDOW_LOCKOUT_S Tff7b72= T79c0ff900
Te6edf3MAX_FAILED_BEFORE_LOCKOUT Tff7b72= T79c0ff5
Te6edf3MAX_TRUSTED_FINGERPRINTS_PER_IDENTITY Tff7b72= T79c0ff100
Tff7b72def Td2a8ffuser_agent_hashTb4b4b4(Te6edf3user_agentTb4b4b4: Tffa657strTb4b4b4) Tff7b72-Tff7b72> Tffa657strTb4b4b4:
Te6edf3raw Tff7b72= Tb4b4b4(Te6edf3user_agent Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffencodeTb4b4b4(Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4, Te6edf3errorsTff7b72=Ta5d6ff"Ta5d6ffreplaceTa5d6ff"Tb4b4b4)
Tff7b72return Te6edf3hashlibTff7b72.Td2a8ffsha256Tb4b4b4(Te6edf3rawTb4b4b4)Tff7b72.Td2a8ffhexdigestTb4b4b4(Tb4b4b4)
Tff7b72class T56d364AccessAttemptsDAOTb4b4b4:
Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4, Te6edf3providerTb4b4b4: Te6edf3DatabaseProviderTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffprovider Tff7b72= Te6edf3provider
Tff7b72def Td2a8ffinsertTb4b4b4(
Tff7b72selfTb4b4b4,
Te6edf3identity_hashTb4b4b4: Tffa657strTb4b4b4,
Te6edf3client_ipTb4b4b4: Tffa657strTb4b4b4,
Te6edf3user_agentTb4b4b4: Tffa657strTb4b4b4,
Te6edf3pathTb4b4b4: Tffa657strTb4b4b4,
Te6edf3methodTb4b4b4: Tffa657strTb4b4b4,
Te6edf3outcomeTb4b4b4: Tffa657strTb4b4b4,
Te6edf3detailTb4b4b4: Tffa657str Tff7b72| Tff7b72None Tff7b72= Tff7b72NoneTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tff7b72NoneTb4b4b4:
Te6edf3ua_short Tff7b72= Tb4b4b4(Te6edf3user_agent Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4)Tb4b4b4[Tb4b4b4:T79c0ff512Tb4b4b4]
Te6edf3ua_h Tff7b72= Te6edf3user_agent_hashTb4b4b4(Te6edf3user_agent Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4)
Te6edf3ts Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffproviderTff7b72.Td2a8ffexecuteTb4b4b4(
T8b949e"""
INSERT INTO access_attempts (
created_at, identity_hash, client_ip, user_agent, user_agent_hash,
path, method, outcome, detail
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
"""Tb4b4b4,
Tb4b4b4(
Te6edf3tsTb4b4b4,
Te6edf3identity_hashTb4b4b4,
Te6edf3client_ip Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4,
Te6edf3ua_shortTb4b4b4,
Te6edf3ua_hTb4b4b4,
Te6edf3pathTb4b4b4,
Te6edf3methodTb4b4b4,
Te6edf3outcomeTb4b4b4,
Te6edf3detailTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72def Td2a8ffis_trustedTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3identity_hashTb4b4b4: Tffa657strTb4b4b4, Te6edf3client_ipTb4b4b4: Tffa657strTb4b4b4, Te6edf3ua_hTb4b4b4: Tffa657strTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
Te6edf3row Tff7b72= Tff7b72selfTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchoneTb4b4b4(
T8b949e"""
SELECT 1 FROM trusted_login_clients
WHERE identity_hash = ? AND client_ip = ? AND user_agent_hash = ?
"""Tb4b4b4,
Tb4b4b4(Te6edf3identity_hashTb4b4b4, Te6edf3client_ip Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3ua_hTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3row Tff7b72is Tff7b72not Tff7b72None
Tff7b72def Td2a8ffupsert_trustedTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3identity_hashTb4b4b4: Tffa657strTb4b4b4, Te6edf3client_ipTb4b4b4: Tffa657strTb4b4b4, Te6edf3ua_hTb4b4b4: Tffa657strTb4b4b4) Tff7b72-Tff7b72> Tff7b72NoneTb4b4b4:
Te6edf3now Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffproviderTff7b72.Td2a8ffexecuteTb4b4b4(
T8b949e"""
INSERT INTO trusted_login_clients (
identity_hash, client_ip, user_agent_hash, last_success_at, created_at
)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT(identity_hash, client_ip, user_agent_hash) DO UPDATE SET
last_success_at = excluded.last_success_at
"""Tb4b4b4,
Tb4b4b4(Te6edf3identity_hashTb4b4b4, Te6edf3client_ip Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3ua_hTb4b4b4, Te6edf3nowTb4b4b4, Te6edf3nowTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_prune_trustedTb4b4b4(Te6edf3identity_hashTb4b4b4)
Tff7b72def Td2a8ff_prune_trustedTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3identity_hashTb4b4b4: Tffa657strTb4b4b4) Tff7b72-Tff7b72> Tff7b72NoneTb4b4b4:
Te6edf3row Tff7b72= Tff7b72selfTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchoneTb4b4b4(
T8b949e"""
SELECT COUNT(*) AS c FROM trusted_login_clients WHERE identity_hash = ?
"""Tb4b4b4,
Tb4b4b4(Te6edf3identity_hashTb4b4b4,Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3count Tff7b72= Te6edf3rowTb4b4b4[Ta5d6ff"Ta5d6ffcTa5d6ff"Tb4b4b4] Tff7b72if Te6edf3row Tff7b72else T79c0ff0
Tff7b72if Te6edf3count Tff7b72<Tff7b72= Te6edf3MAX_TRUSTED_FINGERPRINTS_PER_IDENTITYTb4b4b4:
Tff7b72return
Te6edf3excess Tff7b72= Te6edf3count Tff7b72- Te6edf3MAX_TRUSTED_FINGERPRINTS_PER_IDENTITY
Tff7b72selfTff7b72.Td2a8ffproviderTff7b72.Td2a8ffexecuteTb4b4b4(
T8b949e"""
DELETE FROM trusted_login_clients
WHERE identity_hash = ?
AND rowid IN (
SELECT rowid FROM trusted_login_clients
WHERE identity_hash = ?
ORDER BY last_success_at ASC
LIMIT ?
)
"""Tb4b4b4,
Tb4b4b4(Te6edf3identity_hashTb4b4b4, Te6edf3identity_hashTb4b4b4, Te6edf3excessTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72def Td2a8ffcount_login_attempts_ipTb4b4b4(
Tff7b72selfTb4b4b4,
Te6edf3client_ipTb4b4b4: Tffa657strTb4b4b4,
Te6edf3pathTb4b4b4: Tffa657strTb4b4b4,
Te6edf3since_tsTb4b4b4: Tffa657floatTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657intTb4b4b4:
Te6edf3row Tff7b72= Tff7b72selfTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchoneTb4b4b4(
T8b949e"""
SELECT COUNT(*) AS c FROM access_attempts
WHERE client_ip = ? AND path = ? AND created_at >= ?
"""Tb4b4b4,
Tb4b4b4(Te6edf3client_ip Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3pathTb4b4b4, Te6edf3since_tsTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72return Tffa657intTb4b4b4(Te6edf3rowTb4b4b4[Ta5d6ff"Ta5d6ffcTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72if Te6edf3row Tff7b72else T79c0ff0
Tff7b72def Td2a8ffcount_login_attempts_ip_uaTb4b4b4(
Tff7b72selfTb4b4b4,
Te6edf3client_ipTb4b4b4: Tffa657strTb4b4b4,
Te6edf3ua_hTb4b4b4: Tffa657strTb4b4b4,
Te6edf3pathTb4b4b4: Tffa657strTb4b4b4,
Te6edf3since_tsTb4b4b4: Tffa657floatTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657intTb4b4b4:
Te6edf3row Tff7b72= Tff7b72selfTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchoneTb4b4b4(
T8b949e"""
SELECT COUNT(*) AS c FROM access_attempts
WHERE client_ip = ? AND user_agent_hash = ? AND path = ? AND created_at >= ?
"""Tb4b4b4,
Tb4b4b4(Te6edf3client_ip Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3ua_hTb4b4b4, Te6edf3pathTb4b4b4, Te6edf3since_tsTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72return Tffa657intTb4b4b4(Te6edf3rowTb4b4b4[Ta5d6ff"Ta5d6ffcTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72if Te6edf3row Tff7b72else T79c0ff0
Tff7b72def Td2a8ffcount_lockout_failuresTb4b4b4(
Tff7b72selfTb4b4b4,
Te6edf3identity_hashTb4b4b4: Tffa657strTb4b4b4,
Te6edf3client_ipTb4b4b4: Tffa657strTb4b4b4,
Te6edf3since_tsTb4b4b4: Tffa657floatTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657intTb4b4b4:
Te6edf3row Tff7b72= Tff7b72selfTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchoneTb4b4b4(
T8b949e"""
SELECT COUNT(*) AS c FROM access_attempts aa
WHERE aa.identity_hash = ?
AND aa.client_ip = ?
AND aa.outcome = 'failed_password'
AND aa.created_at >= ?
AND NOT EXISTS (
SELECT 1 FROM trusted_login_clients t
WHERE t.identity_hash = aa.identity_hash
AND t.client_ip = aa.client_ip
AND t.user_agent_hash = aa.user_agent_hash
)
"""Tb4b4b4,
Tb4b4b4(Te6edf3identity_hashTb4b4b4, Te6edf3client_ip Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3since_tsTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72return Tffa657intTb4b4b4(Te6edf3rowTb4b4b4[Ta5d6ff"Ta5d6ffcTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72if Te6edf3row Tff7b72else T79c0ff0
Tff7b72def Td2a8fflist_attemptsTb4b4b4(
Tff7b72selfTb4b4b4,
Te6edf3limitTb4b4b4: Tffa657int Tff7b72= T79c0ff100Tb4b4b4,
Te6edf3offsetTb4b4b4: Tffa657int Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3searchTb4b4b4: Tffa657str Tff7b72| Tff7b72None Tff7b72= Tff7b72NoneTb4b4b4,
Te6edf3outcomeTb4b4b4: Tffa657str Tff7b72| Tff7b72None Tff7b72= Tff7b72NoneTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657listTb4b4b4[Tffa657dictTb4b4b4[Tffa657strTb4b4b4, Te6edf3AnyTb4b4b4]Tb4b4b4]Tb4b4b4:
Te6edf3sql Tff7b72= Ta5d6ff"""
Ta5d6ff SELECT id, created_at, identity_hash, client_ip, user_agent, path, method, outcome, detail
Ta5d6ff FROM access_attempts WHERE 1=1
Ta5d6ff Ta5d6ff"""
Te6edf3paramsTb4b4b4: Tffa657listTb4b4b4[Te6edf3AnyTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72if Te6edf3searchTb4b4b4:
Te6edf3sql Tff7b72+Tff7b72= Ta5d6ff"""Ta5d6ff AND (
Ta5d6ff client_ip LIKE ? OR user_agent LIKE ? OR path LIKE ? OR outcome LIKE ?
Ta5d6ff OR IFNULL(detail,Ta5d6ff'Ta5d6ff'Ta5d6ff) LIKE ?
Ta5d6ff )Ta5d6ff"""
Te6edf3q Tff7b72= Ta5d6fffTa5d6ff"Ta5d6ff%Tffd700{Te6edf3searchTffd700}Ta5d6ff%Ta5d6ff"
Te6edf3paramsTff7b72.Td2a8ffextendTb4b4b4(Tb4b4b4[Te6edf3qTb4b4b4, Te6edf3qTb4b4b4, Te6edf3qTb4b4b4, Te6edf3qTb4b4b4, Te6edf3qTb4b4b4]Tb4b4b4)
Tff7b72if Te6edf3outcomeTb4b4b4:
Te6edf3sql Tff7b72+Tff7b72= Ta5d6ff"Ta5d6ff AND outcome = ?Ta5d6ff"
Te6edf3paramsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3outcomeTb4b4b4)
Te6edf3sql Tff7b72+Tff7b72= Ta5d6ff"Ta5d6ff ORDER BY created_at DESC LIMIT ? OFFSET ?Ta5d6ff"
Te6edf3paramsTff7b72.Td2a8ffextendTb4b4b4(Tb4b4b4[Te6edf3limitTb4b4b4, Te6edf3offsetTb4b4b4]Tb4b4b4)
Te6edf3rows Tff7b72= Tff7b72selfTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchallTb4b4b4(Te6edf3sqlTb4b4b4, Tffa657tupleTb4b4b4(Te6edf3paramsTb4b4b4)Tb4b4b4)
Tff7b72return Tb4b4b4[Tffa657dictTb4b4b4(Te6edf3rTb4b4b4) Tff7b72for Te6edf3r Tff7b72in Te6edf3rowsTb4b4b4]
Tff7b72def Td2a8ffcount_attemptsTb4b4b4(
Tff7b72selfTb4b4b4,
Te6edf3searchTb4b4b4: Tffa657str Tff7b72| Tff7b72None Tff7b72= Tff7b72NoneTb4b4b4,
Te6edf3outcomeTb4b4b4: Tffa657str Tff7b72| Tff7b72None Tff7b72= Tff7b72NoneTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657intTb4b4b4:
Te6edf3sql Tff7b72= Ta5d6ff"Ta5d6ffSELECT COUNT(*) AS c FROM access_attempts WHERE 1=1Ta5d6ff"
Te6edf3paramsTb4b4b4: Tffa657listTb4b4b4[Te6edf3AnyTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72if Te6edf3searchTb4b4b4:
Te6edf3sql Tff7b72+Tff7b72= Ta5d6ff"""Ta5d6ff AND (
Ta5d6ff client_ip LIKE ? OR user_agent LIKE ? OR path LIKE ? OR outcome LIKE ?
Ta5d6ff OR IFNULL(detail,Ta5d6ff'Ta5d6ff'Ta5d6ff) LIKE ?
Ta5d6ff )Ta5d6ff"""
Te6edf3q Tff7b72= Ta5d6fffTa5d6ff"Ta5d6ff%Tffd700{Te6edf3searchTffd700}Ta5d6ff%Ta5d6ff"
Te6edf3paramsTff7b72.Td2a8ffextendTb4b4b4(Tb4b4b4[Te6edf3qTb4b4b4, Te6edf3qTb4b4b4, Te6edf3qTb4b4b4, Te6edf3qTb4b4b4, Te6edf3qTb4b4b4]Tb4b4b4)
Tff7b72if Te6edf3outcomeTb4b4b4:
Te6edf3sql Tff7b72+Tff7b72= Ta5d6ff"Ta5d6ff AND outcome = ?Ta5d6ff"
Te6edf3paramsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3outcomeTb4b4b4)
Te6edf3row Tff7b72= Tff7b72selfTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchoneTb4b4b4(Te6edf3sqlTb4b4b4, Tffa657tupleTb4b4b4(Te6edf3paramsTb4b4b4)Tb4b4b4)
Tff7b72return Tffa657intTb4b4b4(Te6edf3rowTb4b4b4[Ta5d6ff"Ta5d6ffcTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72if Te6edf3row Tff7b72else T79c0ff0
Tff7b72def Td2a8ffcleanup_oldTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3max_rowsTb4b4b4: Tffa657int Tff7b72= T79c0ff50_000Tb4b4b4) Tff7b72-Tff7b72> Tff7b72NoneTb4b4b4:
Te6edf3row Tff7b72= Tff7b72selfTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchoneTb4b4b4(Ta5d6ff"Ta5d6ffSELECT COUNT(*) AS c FROM access_attemptsTa5d6ff"Tb4b4b4)
Te6edf3count Tff7b72= Tffa657intTb4b4b4(Te6edf3rowTb4b4b4[Ta5d6ff"Ta5d6ffcTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72if Te6edf3row Tff7b72else T79c0ff0
Tff7b72if Te6edf3count Tff7b72<Tff7b72= Te6edf3max_rowsTb4b4b4:
Tff7b72return
Te6edf3excess Tff7b72= Te6edf3count Tff7b72- Te6edf3max_rows
Tff7b72selfTff7b72.Td2a8ffproviderTff7b72.Td2a8ffexecuteTb4b4b4(
T8b949e"""
DELETE FROM access_attempts WHERE rowid IN (
SELECT rowid FROM access_attempts ORDER BY created_at ASC LIMIT ?
)
"""Tb4b4b4,
Tb4b4b4(Te6edf3excessTb4b4b4,Tb4b4b4)Tb4b4b4,
Tb4b4b4)
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────